/*
 * Logger クラス (シングルトン)．
 *
 * @author krdlab
 */
#ifndef __NIGHT_SKY_LOGGER_H
#define __NIGHT_SKY_LOGGER_H
#include <string>
#include <iosfwd>

namespace night_sky
{
  /**
   * ロガークラス．
   * setup 関数の呼び出し規約さえ守れば，シングルトンとして扱える．
   * 
   * @author krdlab
   */
  class Logger
  {
  private:
    struct Impl* m_pimpl;

  private:
    Logger();
    Logger(const Logger&);
    Logger& operator=(const Logger&);

    void initialize(const std::string& conf_path, const std::string& category);
    void destroy();

  public:
    ~Logger();

    void debug(const std::string& msg);
    void info(const std::string& msg);
    void warn(const std::string& msg);
    void error(const std::string& msg);
    void fatal(const std::string& msg);

    bool isInfoEnabled() const;
    bool isWarnEnabled() const;
    bool isErrorEnabled() const;

  public:
    /**
     * ロガーを設定する．
     * 必ず main 関数で呼び出すこと．
     * 
     * @param conf_path
     *         設定ファイルのパス
     * @param category
     *         ロガーのカテゴリを指定
     */
    static void setup(const std::string& conf_path, const std::string& category);

    /**
     * ロガーを取得する．
     * 
     * @return {@link Logger}
     *         シングルトンインスタンス
     */
    static Logger& getInstance();
  };

}// namespace night_sky

#define __NS_LOGGER_XXX(logger, Mode, method, oss_arg)\
{\
  if (logger.is ## Mode ## Enabled()) {\
    std::ostringstream ss;\
    ss oss_arg;\
    logger.method(ss.str());\
  }\
}

// debug
#define __NS_LOGGER_DEBUG(logger, oss_arg)\
__NS_LOGGER_XXX(logger, Debug, debug, oss_arg)

#define NS_LOGGER_DEBUG_2(logger, arg1, arg2)\
__NS_LOGGER_DEBUG((logger), << (arg1) << (arg2))

// info
#define __NS_LOGGER_INFO(logger, oss_arg)\
__NS_LOGGER_XXX(logger, Info, info, oss_arg)

#define NS_LOGGER_INFO_1(logger, arg1)\
__NS_LOGGER_INFO((logger), << (arg1))

#define NS_LOGGER_INFO_2(logger, arg1, arg2)\
__NS_LOGGER_INFO((logger), << (arg1) << (arg2))

#define NS_LOGGER_INFO_3(logger, arg1, arg2, arg3)\
__NS_LOGGER_INFO((logger), << (arg1) << (arg2) << (arg3))

#define NS_LOGGER_INFO_4(logger, arg1, arg2, arg3, arg4)\
__NS_LOGGER_INFO((logger), << (arg1) << (arg2) << (arg3) << (arg4))

#define NS_LOGGER_INFO_5(logger, arg1, arg2, arg3, arg4, arg5)\
__NS_LOGGER_INFO((logger), << (arg1) << (arg2) << (arg3) << (arg4) << (arg5))

// warn
#define __NS_LOGGER_WARN(logger, oss_arg)\
__NS_LOGGER_XXX(logger, Warn, warn, oss_arg)

#define NS_LOGGER_WARN_2(logger, arg1, arg2)\
__NS_LOGGER_WARN((logger), << (arg1) << (arg2))

// error
#define __NS_LOGGER_ERROR(logger, oss_arg)\
__NS_LOGGER_XXX(logger, Error, error, oss_arg)

#define NS_LOGGER_ERROR_1(logger, arg1)\
__NS_LOGGER_ERROR((logger), << (arg1))

#define NS_LOGGER_ERROR_2(logger, arg1, arg2)\
__NS_LOGGER_ERROR((logger), << (arg1) << (arg2))

#define NS_LOGGER_ERROR_3(logger, arg1, arg2, arg3)\
__NS_LOGGER_ERROR((logger), << (arg1) << (arg2) << (arg3))

#define NS_LOGGER_ERROR_5(logger, arg1, arg2, arg3, arg4, arg5)\
__NS_LOGGER_ERROR((logger), << (arg1) << (arg2) << (arg3) << (arg4) << (arg5))

#endif
